//
//  Base64.m
//  HZ_New_Stock
//
//  Created by gaotime on 16/8/4.
//  Copyright © 2016年 Zeroing. All rights reserved.
//

#import "Base64.h"

static const char _bas64EncodingTable[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const short _base64DecodingTable[256] = {
  -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -1, -1, -2, -2,
  -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
  -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63,
  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -2, -2, -2,
  -2,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2,
  -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2,
  -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
  -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
  -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
  -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
  -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
  -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
  -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
  -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
};

@implementation Based64

+ (NSString *)encodeBase64WithString:(NSString *)strData {
  return [Based64 encodeBase64WithData:[strData dataUsingEncoding:NSUTF8StringEncoding]];
}


+ (NSString *)encodeBase64WithData:(NSData *)objData {
  const unsigned char * objRawData = [objData bytes];
  char * objPointer;
  char * strResult;
  
  int intLength = [objData length];
  if (intLength == 0) return nil;
  
  strResult = (char *)calloc(((intLength + 2) / 3) * 4, sizeof(char));
  objPointer = strResult;
  
  while(intLength > 2) {
    *objPointer++ = _bas64EncodingTable[objRawData[0] >> 2];
    *objPointer++ = _bas64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
    *objPointer++ = _bas64EncodingTable[((objRawData[1] & 0x0f) << 2) + (objRawData[2] >> 6)];
    *objPointer++ = _bas64EncodingTable[objRawData[2] & 0x3f];
    
    objRawData += 3;
    intLength -= 3;
  }
  
  if (intLength != 0) {
    *objPointer++ = _bas64EncodingTable[objRawData[0] >> 2];
    if (intLength > 1) {
      *objPointer++ = _bas64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
      *objPointer++ = _bas64EncodingTable[(objRawData[1] & 0x0f) << 2];
      *objPointer++ = '=';
    } else {
      *objPointer++ = _bas64EncodingTable[(objRawData[0] & 0x03) << 4];
      *objPointer++ = '=';
      *objPointer++ = '=';
    }
  }
  
  *objPointer = '\0';
  
  return[NSString stringWithCString:strResult encoding:NSASCIIStringEncoding];
}


+ (NSData *)decodeBase64WithString:(NSString *)strBase64 {
  const char* objPointer = [strBase64 cStringUsingEncoding:NSASCIIStringEncoding];
  int intLength = strlen(objPointer);
  int intCurrent;
  int i = 0, j = 0, k;
  
  unsigned char * objResult;
  objResult = calloc(intLength, sizeof(char));
  
  while ( ((intCurrent = *objPointer++) != '\0') && (intLength-- > 0) ) {
    if (intCurrent == '=') {
      if (*objPointer != '=' && ((i % 4) == 1)) {// || (intLength > 0)) {
        free(objResult);
        return nil;
      }
      continue;
    }
    
    intCurrent = _base64DecodingTable[intCurrent];
    if (intCurrent == -1) {
      continue;
    } else if (intCurrent == -2) {
      free(objResult);
      return nil;
    }
    
    switch (i % 4) {
      case 0:
        objResult[j] = intCurrent << 2;
        break;
        
      case 1:
        objResult[j++] |= intCurrent >> 4;
        objResult[j] = (intCurrent & 0x0f) << 4;
        break;
        
      case 2:
        objResult[j++] |= intCurrent >>2;
        objResult[j] = (intCurrent & 0x03) << 6;
        break;
        
      case 3:
        objResult[j++] |= intCurrent;
        break;
    }
    i++;
  }
  
  k = j;
  if (intCurrent == '=') {
    switch (i % 4) {
      case 1:
        free(objResult);
        return nil;
      case 2:
        k++;
      case 3:
        objResult[k] = 0;
    }
  }
  
  NSData * objData = [[NSData alloc] initWithBytes:objResult length:j] ;
  free(objResult);
  return objData;
}


@end
